package com.easyboot.web.system.service;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.easyboot.cache.PermissionCache;
import com.easyboot.framework.exception.EasyException;
import com.easyboot.utils.CommonUtil;
import com.easyboot.utils.IdHelper;
import com.easyboot.framework.domain.DataTableDto;
import com.easyboot.framework.domain.KeyValueInt64Dto;
import com.easyboot.framework.domain.ZtreeDto;
import com.easyboot.enums.DataStatusEnum;
import com.easyboot.framework.shiro.UserOwnInfo;
import com.easyboot.utils.log.LoggerHelper;
import com.easyboot.web.system.domain.SysMenu;
import com.easyboot.web.system.domain.SysOperate;
import com.easyboot.web.system.domain.SysRole;
import com.easyboot.web.system.domain.SysRoleAuthorize;
import com.easyboot.web.system.dto.RoleButtonPermissionDto;
import com.easyboot.web.system.mapper.SysMenuMapper;
import com.easyboot.web.system.mapper.SysOperateMapper;
import com.easyboot.web.system.mapper.SysRoleAuthorizeMapper;
import com.easyboot.web.system.mapper.SysRoleMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author yushuo
 * @className
 * @descripton TODO
 * @date 2021/2/1 16:27
 **/
@Service
public class SysRoleService {

    @Autowired
    private SysRoleMapper roleMapper;
    @Autowired
    private SysMenuMapper menuMapper;
    @Autowired
    private SysOperateMapper operateMapper;
    @Autowired
    private SysRoleAuthorizeMapper roleAuthorizeMapper;
    /**
    *
     * @author yushuo
     * @description //角色列表
     * @date 16:38 2021/2/1
     * @param [dto, roleName, roleCode]
     * @return com.easycms.framework.domain.DataTableDto
    **/
    public DataTableDto getRoleList(DataTableDto dto,String roleName,String roleCode){
        LambdaQueryWrapper<SysRole> query=new LambdaQueryWrapper<>();
         if(!StrUtil.isEmpty(roleName)){
             query.like(SysRole::getRoleName,roleName.trim());
         }
        if(!StrUtil.isEmpty(roleCode)){
            query.like(SysRole::getRoleCode,roleCode.trim());
        }
        query.orderByAsc(SysRole::getRoleSort);
        Page<SysRole> page = new Page<>(dto.getPageNumber(), dto.getPageSize());
        IPage<SysRole> userIPage = roleMapper.selectPage(page, query);
        dto.setTotal(userIPage.getTotal());
        dto.setRows(userIPage.getRecords());
        return dto;
    }

    /**
    *
     * @author yushuo
     * @description //角色下拉列表
     * @date 12:06 2021/2/2
     * @param []
     * @return java.util.List<com.easycms.framework.domain.KeyValueInt64Dto>
    **/
    public List<KeyValueInt64Dto> getRoles(){
        LambdaQueryWrapper<SysRole> query=new LambdaQueryWrapper<>();
        query.eq(SysRole::getRoleSuper, DataStatusEnum.NOT_SUPER.getCode())
        .eq(SysRole::getRoleStatus, DataStatusEnum.ENABLE.getCode())
                .select(SysRole::getId, SysRole::getRoleName)
                .orderByAsc(SysRole::getRoleSort);

        List<KeyValueInt64Dto> data=new ArrayList<>();
        List<SysRole> roles=roleMapper.selectList(query);
        roles.stream().forEach(r->{
            KeyValueInt64Dto dto=new KeyValueInt64Dto();
            dto.setId(r.getId());
            dto.setName(r.getRoleName());
            data.add(dto);
        });

        return data;
    }

    /**
    *
     * @author yushuo
     * @description //TODO
     * @date 10:33 2021/2/2
     * @param [id]
     * @return com.easycms.web.system.domain.SysRole
    **/
    public SysRole getModel(Long id){
        SysRole role= roleMapper.selectById(id);
        return role;
    }


    /**
    *
     * @author yushuo
     * @description //save
     * @date 10:33 2021/2/2
     * @param [role]
     * @return void
    **/
    public void save(SysRole role, UserOwnInfo userOwnInfo){
        if(role.getRoleStatus()==0){
            role.setRoleStatus(DataStatusEnum.DISABLE.getCode());
        }
        role.setRoleSuper(DataStatusEnum.NOT_SUPER.getCode());
        if(role.getId()==0){
            role.setId(IdHelper.nextId());
            role.setCreateTime(DateUtil.date());
            role.setCreatePerson("admin");
            roleMapper.insert(role);
            return;
        }
        SysRole oldRole=getModel(role.getId());
        if(oldRole!=null){
            role.setCreatePerson(oldRole.getCreatePerson());
            role.setCreateTime(oldRole.getCreateTime());
            roleMapper.updateById(role);
        }

    }

    /**
    *
     * @author yushuo
     * @description //删除角色
     * @date 10:33 2021/2/2
     * @param [id]
     * @return void
    **/
    public void removeRole(String ids){
        List<Long> idArray = Arrays.asList(Convert.toLongArray(ids)) ;
        roleMapper.deleteBatchIds(idArray);
    }


    /**
    *
     * @author yushuo
     * @description //角色权限列表
     * @date 14:23 2021/2/22
     * @param [roleId]
     * @return java.util.List<com.easycms.framework.domain.ZtreeDto>
    **/
    public List<ZtreeDto> getRoleMenuList(long roleId){
        List<ZtreeDto> roleMenuList=new ArrayList<>();
        //获取菜单列表
        LambdaQueryWrapper<SysMenu> query=new LambdaQueryWrapper<>();
        query.select(SysMenu::getId, SysMenu::getMenuName,SysMenu::getParentId)
                .orderByAsc(SysMenu::getMenuSort);
        List<SysMenu> menuList=menuMapper.selectList(query);

        if(menuList.size()>0){
            //获取按钮列表
            List<Long> menuIds=menuList.stream().map(s->s.getId()).collect(Collectors.toList());

            LambdaQueryWrapper<SysOperate> operateQuery=new LambdaQueryWrapper<>();
            operateQuery.in(SysOperate::getMenuId,menuIds);
            List<SysOperate> operateList=operateMapper.selectList(operateQuery);
            //获取角色权限
            LambdaQueryWrapper<SysRoleAuthorize> permsQuery=new LambdaQueryWrapper<>();
            permsQuery.eq(SysRoleAuthorize::getRoleId,roleId);
            List<SysRoleAuthorize> roleAuthorizeList=roleAuthorizeMapper.selectList(permsQuery);
            int permsCount = roleAuthorizeList.size();

            //设置菜单选中
            for (SysMenu menu:menuList){
                ZtreeDto ztreeDto=new ZtreeDto();
                ztreeDto.setId(menu.getId().toString());
                ztreeDto.setPId(menu.getParentId().toString());
                ztreeDto.setName(menu.getMenuName());
                if(permsCount>0){
                    long menuId=menu.getId();
                    long menuPId=menu.getParentId();

                    Optional<SysRoleAuthorize> hasPerms=  roleAuthorizeList.stream()
                          .filter(s ->s.getMenuId()==menuId )
                          .findFirst();
                    if(hasPerms.isPresent()){
                        ztreeDto.setCheckstate(true);
                    }

                }
                roleMenuList.add(ztreeDto);
            }

            //设置按钮选中
            for (SysOperate operate:operateList){
                ZtreeDto ztreeDto=new ZtreeDto();
                ztreeDto.setId(operate.getId().toString());
                ztreeDto.setPId(operate.getMenuId().toString());
                ztreeDto.setName(operate.getFuncTitle());
                if(permsCount>0){
                    long menuId=operate.getId();
                    long menuPId=operate.getMenuId();
                    Optional<SysRoleAuthorize> hasPerms=  roleAuthorizeList.stream()
                            .filter(s ->s.getMenuId()==menuId)//&&s.getMenuPid()==menuPId
                            .findFirst();
                    if(hasPerms.isPresent()){
                        ztreeDto.setCheckstate(true);
                    }
                }
                roleMenuList.add(ztreeDto);
            }
        }

        return roleMenuList;

    }
    
    
    /**
    *
     * @author yushuo
     * @description //TODO
     * @date 15:20 2021/2/22
     * @param [roleId, permissions]
     * @return void
    **/
    @Transactional(rollbackOn = EasyException.class)
    public void savePermissions(Long roleId,List<ZtreeDto> permissions,String accountName){

        LambdaQueryWrapper<SysRoleAuthorize> query=new LambdaQueryWrapper<>();
        query.eq(SysRoleAuthorize::getRoleId,roleId);
        roleAuthorizeMapper.delete(query);

        if(permissions.size()>0){
            Date now=DateUtil.date();
              List<SysRoleAuthorize> roleAuthorizeList=new ArrayList<>();
              for (ZtreeDto ztreeDto:permissions){

                  SysRoleAuthorize model=new SysRoleAuthorize();
                  model.setId(IdHelper.nextId());
                  model.setRoleId(roleId);
                  model.setMenuId(Convert.toLong(ztreeDto.getId()));
                  model.setMenuPid(Convert.toLong(ztreeDto.getPId()));
                  model.setCreateTime(now);
                  model.setCreatePerson(accountName);
                  roleAuthorizeList.add(model);
              }

            roleAuthorizeMapper.insertAll(roleAuthorizeList);
        }

        //每次变更权限后移除缓存
        PermissionCache.removeRolePermission(roleId);
    }

    /**
     *
     * @author yushuo
     * @description 获取角色的所有的权限标识
     * @date 15:20 2021/2/22
     * @param [roleId, permissions]
     * @return void
     **/
    public HashSet<String> getPermissionTags(Long roleId){
        HashSet<String> permissionTags=new HashSet<>();
        if(roleId==0){
            return permissionTags;
        }

        //获取角色权限标识缓存
        HashSet<String> permissionTagsCache= PermissionCache.getRolePermissions(roleId);
        if(permissionTagsCache.size()>0){
            return permissionTagsCache;
        }
        List<SysMenu> menus=menuMapper.selectMenuRoleTags(roleId);
        List<SysOperate> operates=operateMapper.selectOperateRoleTags(roleId);


        //按钮权限
        if(menus.size()>0){
            menus.stream().forEach(s->{
                if(!"#".equals(s.getRoleTag())){
                    permissionTags.add(s.getRoleTag());
                }

            });
        }

        //按钮权限
        List<RoleButtonPermissionDto> buttonPermissionList=new ArrayList<>();
        if(operates.size()>0){
            //后台按钮权限
            operates.stream().forEach(s->{
                permissionTags.add(s.getRoleTag());
            });

            //前台按钮权限
            List<Long> menuIds=operates.stream().map(s->s.getMenuId()).distinct().collect(Collectors.toList());

            menuIds.stream().forEach(m->{
                Optional<SysMenu> sysMenu=menus.stream().filter(s->s.getId().equals(m)).findFirst();
                if(sysMenu.isPresent()){
                    List<SysOperate> buttons=operates.stream().filter(s->s.getMenuId()==m.longValue()).collect(Collectors.toList());
                    if(buttons.size()>0){
                        RoleButtonPermissionDto buttonPermissionDto=new RoleButtonPermissionDto();
                        buttonPermissionDto.setMenuId(CommonUtil.getMenuTabId(sysMenu.get().getMenuUrl()));
                        for (SysOperate operate:buttons){
                            buttonPermissionDto.put(operate.getRoleTag());

                        }
                        buttonPermissionList.add(buttonPermissionDto);
                    }
                }

            });
        }
        //添加缓存 后台菜单和按钮
        if(permissionTags.size()>0){
            PermissionCache.addRolePermission(roleId,permissionTags);
        }

        //添加缓存 前台按钮
        if(buttonPermissionList.size()>0){
            PermissionCache.addRoleButtonPermission(roleId,buttonPermissionList);
        }
        return permissionTags;
    }


    /**
    *
     * @author yushuo
     * @description 获取角色前台的按钮权限
     * @date 15:29 2021/2/23
     * @param [roleId]
     * @return java.util.List<com.easycms.web.system.dto.RoleButtonPermissionDto>
    **/
    public List<RoleButtonPermissionDto> getButtonPermissionList(long roleId){
       List<RoleButtonPermissionDto> permissionTags=new ArrayList<>();
        if(roleId==0){
            return permissionTags;
        }

        //获取角色权限标识缓存
        List<RoleButtonPermissionDto> permissionTagsCache= PermissionCache.getRoleButtonPermissions(roleId);
        if(permissionTagsCache.size()>0){
            //LoggerHelper.console("from cache button permissions");
            return permissionTagsCache;
        }

        List<SysOperate> operates=operateMapper.selectOperateRoleTags(roleId);
        if(operates.size()>0){
            List<Long> menuIds=operates.stream().map(s->s.getMenuId()).distinct().collect(Collectors.toList());
            LambdaQueryWrapper<SysMenu> menuQuery= Wrappers.lambdaQuery();
            menuQuery.in(SysMenu::getId,menuIds);
            List<SysMenu> menus=menuMapper.selectList(menuQuery);
            menus.stream().forEach(m->{

                    List<SysOperate> buttons=operates.stream().filter(s->s.getMenuId().equals(m.getId())).collect(Collectors.toList());
                    if(buttons.size()>0){
                        RoleButtonPermissionDto buttonPermissionDto=new RoleButtonPermissionDto();
                        buttonPermissionDto.setMenuId(CommonUtil.getMenuTabId(m.getMenuUrl()));
                        for (SysOperate operate:buttons){
                            buttonPermissionDto.put(operate.getRoleTag());

                        }
                        permissionTags.add(buttonPermissionDto);
                    }
            });

            //添加缓存
            if(permissionTags.size()>0){
               // LoggerHelper.console("write cache from database button permissions");
                PermissionCache.addRoleButtonPermission(roleId,permissionTags);
            }
        }
        //LoggerHelper.console("from database button permissions");
        return permissionTags;
    }


    /**
    *
     * @author yushuo
     * @description 获取角色权限菜单
     * @date 15:08 2021/2/24
     * @param [roleId]
     * @return java.util.List<com.easycms.web.system.domain.SysMenu>
    **/
    public List<SysMenu> getPermissionMenus(Long roleId){
        if(roleId==0){
            return new ArrayList<>();
        }
        List<SysMenu> menus=menuMapper.selectMenuRoleTags(roleId);
        if(menus.size()>0){
            //一级菜单
            List<SysMenu> tops=menus.stream().filter(menu->menu.getParentId()==0L)
                    .collect(Collectors.toList());

            tops.forEach(menu->{
                menu.setTabId(CommonUtil.getMenuTabId(menu.getMenuUrl()));
                //二级菜单
                long pid=menu.getId();
                List<SysMenu> sons=menus.stream().filter(m->m.getParentId()==pid).collect(Collectors.toList());
                sons.forEach(son->{
                    son.setTabId(CommonUtil.getMenuTabId(son.getMenuUrl()));
                    //三级菜单
                    long sonPid=son.getId();
                    List<SysMenu> sons2=menus.stream().filter(m->m.getParentId()==sonPid).collect(Collectors.toList());
                    sons2.forEach(s->{
                        s.setTabId(CommonUtil.getMenuTabId(s.getMenuUrl()));
                    });
                    son.setChildren(sons2);
                });
                menu.setChildren(sons);
            });

            return tops;
        }
        return menus;
    }


}
